import {
  Controller,
  Post,
  Body,
  UseGuards,
  ConflictException,
  HttpStatus,
  HttpCode,
  Param,
  Put,
  Patch,
  NotFoundException,
  BadRequestException,
  Req,
  Get,
  Query,
} from '@nestjs/common';
import {
  ApiTags,
  ApiOperation,
  ApiResponse,
  ApiConflictResponse,
  ApiBearerAuth,
  ApiParam,
  ApiNotFoundResponse,
  ApiBadRequestResponse,
} from '@nestjs/swagger';
import { JwtAuthGuard } from '../auth/guards/jwt-auth.guard';
import { RolesGuard } from '../auth/guards/roles.guard';
import { Roles } from '../auth/decorators/roles.decorator';
import { UserRole, DeviceStatus } from '../common/enums';
import { DevicesService } from './devices.service';
import {
  CreateDeviceDto,
  BindDeviceDto,
  UpdateDeviceStatusDto,
  UpdateDeviceMetadataDto,
  DeviceListResponseDto,
} from './dto';
import { DeviceAdminModel } from './models';

@ApiTags('Device')
@Controller('devices')
@UseGuards(JwtAuthGuard, RolesGuard)
@Roles(UserRole.ADMIN)
@ApiBearerAuth()
export class DevicesController {
  constructor(private readonly devicesService: DevicesService) {}

  @Post()
  @ApiOperation({ summary: '注册新设备（仅管理员）' })
  @ApiResponse({
    status: HttpStatus.CREATED,
    description: 'Device registered successfully',
    type: DeviceAdminModel,
  })
  @ApiConflictResponse({
    description: 'Device with the provided serial number already exists',
  })
  async registerDevice(
    @Body() createDeviceDto: CreateDeviceDto,
    @Req() req: any,
  ): Promise<DeviceAdminModel> {
    try {
      return await this.devicesService.registerDevice(createDeviceDto, req.user.userId);
    } catch (error) {
      if (error instanceof ConflictException) {
        throw error;
      }
      throw error;
    }
  }

  @Put(':deviceId/binding')
  @HttpCode(HttpStatus.OK)
  @ApiOperation({ summary: '绑定设备到用户（仅管理员）' })
  @ApiParam({ name: 'deviceId', description: 'Device ID', required: true })
  @ApiResponse({
    status: HttpStatus.OK,
    description: 'Device bound to user successfully',
    type: DeviceAdminModel,
  })
  @ApiNotFoundResponse({
    description: 'Device or user not found4',
  })
  async bindDeviceToUser(
    @Param('deviceId') deviceId: string,
    @Body() bindDeviceDto: BindDeviceDto,
    @Req() req: any,
  ): Promise<DeviceAdminModel> {
    try {
      return await this.devicesService.bindDeviceToUser(deviceId, bindDeviceDto, req.user.userId);
    } catch (error) {
      if (error instanceof NotFoundException) {
        throw error;
      }
      throw error;
    }
  }

  @Patch(':deviceId/status')
  @HttpCode(HttpStatus.OK)
  @ApiOperation({ summary: '更新设备状态（仅管理员）' })
  @ApiParam({ name: 'deviceId', description: 'Device ID' })
  @ApiResponse({
    status: HttpStatus.OK,
    description: 'Device status updated successfully',
    type: DeviceAdminModel,
  })
  @ApiNotFoundResponse({
    description: 'Device not found',
  })
  @ApiBadRequestResponse({
    description: 'Invalid status transition or missing required fields',
  })
  async updateDeviceStatus(
    @Param('deviceId') deviceId: string,
    @Body() updateStatusDto: UpdateDeviceStatusDto,
    @Req() req: any,
  ): Promise<DeviceAdminModel> {
    try {
      return await this.devicesService.updateDeviceStatus(
        deviceId,
        updateStatusDto,
        req.user.userId,
      );
    } catch (error) {
      if (error instanceof NotFoundException || error instanceof BadRequestException) {
        throw error;
      }
      throw error;
    }
  }

  @Patch(':deviceId')
  @HttpCode(HttpStatus.OK)
  @ApiOperation({ summary: '更新设备元数据（仅管理员）' })
  @ApiParam({ name: 'deviceId', description: 'Device ID' })
  @ApiResponse({
    status: HttpStatus.OK,
    description: 'Device metadata updated successfully',
    type: DeviceAdminModel,
  })
  @ApiNotFoundResponse({
    description: 'Device not found',
  })
  async updateDeviceMetadata(
    @Param('deviceId') deviceId: string,
    @Body() updateMetadataDto: UpdateDeviceMetadataDto,
    @Req() req: any,
  ): Promise<DeviceAdminModel> {
    try {
      return await this.devicesService.updateDeviceMetadata(
        deviceId,
        updateMetadataDto,
        req.user.userId,
      );
    } catch (error) {
      if (error instanceof NotFoundException) {
        throw error;
      }
      throw error;
    }
  }

  @Get()
  @ApiOperation({ summary: '获取设备列表（仅管理员）' })
  @ApiResponse({
    status: HttpStatus.OK,
    description: 'List of devices',
    type: DeviceListResponseDto,
  })
  async findAll(
    @Req() req: any,
    @Query('status') status?: DeviceStatus,
    @Query('userId') userId?: string,
    @Query('page') page: number = 1,
    @Query('limit') limit: number = 10,
  ): Promise<DeviceListResponseDto> {
    // Regular users can only see their own devices
    if (req.user.role !== UserRole.ADMIN) {
      userId = req.user.userId;
    }

    const result = await this.devicesService.findAll({
      status,
      userId,
      page,
      limit,
    });

    return {
      data: result.items,
      pagination: {
        total: result.meta.total,
        page: Number(result.meta.page),
        pageSize: Number(result.meta.limit),
      },
    };
  }

  @Get(':deviceId')
  @ApiOperation({ summary: '获取设备详情（仅管理员）' })
  @ApiParam({ name: 'deviceId', description: 'Device ID', required: true })
  @ApiResponse({
    status: HttpStatus.OK,
    description: 'Device details',
    type: DeviceAdminModel,
  })
  @ApiNotFoundResponse({
    description: 'Device not found',
  })
  async getDeviceDetails(
    @Param('deviceId') deviceId: string,
    @Req() req: any,
  ): Promise<DeviceAdminModel> {
    try {
      return await this.devicesService.getDeviceDetails(deviceId, req.user.role, req.user.userId);
    } catch (error) {
      if (error instanceof NotFoundException) {
        throw error;
      }
      throw error;
    }
  }
}
